#include "nes_main.h"
//#include "nes_ppu.h"
#include "vnes/ppu_vnes.h"
#include "nes_mapper.h"
#include "nes_apu.h"
#include "sys_gpio.h"
#include <stdlib.h>
#include "sys_timer.h"
#include "sys_delay.h"
#include "sys_owa.h"
#include "sys_uart.h"
#include "ff.h"
#include <string.h>
#include <stdio.h>
//--------------
#include "sys_lcd_conf.h"
#include "sys_touch_conf.h"
//--------------
#include "sys_defe.h"
#include "sys_spi.h"
#include "FreeRTOS.h"

// 1280x720 @ RGB565
// XSIZE_PHYS YSIZE_PHYS
#define VRAM_BASE 0x81800000

#ifndef EVB_IO
#define ENABLE_USER_KEY // GPIO A0
#endif

#define NES_VER_DENDY

#ifdef NES_VER_DENDY
#define SCAN_LINE_NMI   291
#define SCAN_LINE_TOTAL 312
//#elif defined(NES_VER_NTSC)
#else
// default is NTSC
#define SCAN_LINE_NMI   241
#define SCAN_LINE_TOTAL 262
#endif

typedef struct tagNESCONFIG {
	FLOAT	BaseClock;		// NTSC:21477270.0  PAL:21281364.0
	FLOAT	CpuClock;		// NTSC: 1789772.5  PAL: 1773447.0

	INT	TotalScanlines;		// NTSC: 262  PAL: 312
	INT VBlankLine;			// NTSC: 241  PAL: 291

	INT	ScanlineCycles;		// NTSC:1364  PAL:1362

	INT	HDrawCycles;		// NTSC:1024  PAL:1024
	INT	HBlankCycles;		// NTSC: 340  PAL: 338
	INT	ScanlineEndCycles;	// NTSC:   4  PAL:   2

	INT	FrameCycles;		// NTSC:29829.52  PAL:35468.94
	INT	FrameIrqCycles;		// NTSC:29829.52  PAL:35468.94

	INT	FrameRate;			// NTSC:60(59.94) PAL:50
	FLOAT	FramePeriod;	// NTSC:16.683    PAL:20.0
} NESCONFIG, * LPNESCONFIG;

NESCONFIG NESCONFIG_DENDY = {
	26601712.0f,	// Base clock
	1773447.0f,		// Cpu clock

	312,			// Total scanlines
	291,			// VBlank start line

	1364,			// Scanline total cycles(15.625KHz)

//	1024,			// H-Draw cycles
	1028,			// fine tuning of H-Draw cycles

	338,			// H-Blank cycles
	2,				// End cycles

	1364 * 312,		// Frame cycles
	35464,			// FrameIRQ cycles

	50,				// Frame rate(Hz)
	1000.0f / 50.0f	// Frame period(ms)
};

#define	FETCH_CYCLES	8

#define SRAMIN 0

// D2:Scroll/D1:Caps/D0:Num
extern unsigned char kbd_led_ctl; // in Driver/Source/ch9350_input.c
extern volatile unsigned char key_bitmap[32];

// in main.c
extern int is_emu_running;
extern volatile int event_gui_done;

#define KEY_SCODE(c) (key_bitmap[(c) / 8] & 1 << ((c) % 8))

extern void Joy_Reset();
extern int emu_hard_reset; // in desktop.c
extern int emu_video_filter; // in desktop.c
void* mymalloc(int s, int size)
{
	void* o;

//	o = malloc(size);
	o = pvPortMalloc(size);

	if (!o) {
		sysprintf("malloc %d err.\r\n", size);
	} else {
		sysprintf("malloc %d -> %08X.\r\n", size, o);
	}

	if ((unsigned int)o & 0x3) {
		sysprintf("malloc err...\r\n");
	}

	return o;
}

void myfree(int s, void * d)
{
//	free(d);
	vPortFree(d);
}

#define vu8 unsigned char

void mymemset(void *s, u8 c, u32 count)
{
	u8* xs = s;
	while (count--) *xs++ = c;
}


extern u8 frame;		//nes帧计数器
u8 nes_frame_cnt;		//nes帧计数器
int MapperNo;			//map编号
int NES_scanline;		//nes扫描线
int VROM_1K_SIZE;
int VROM_8K_SIZE;
u32 NESrom_crc32;

int PADdata0;   			//手柄1键值 [7:0]右7 左6 下5 上4 Start3 Select2 B1 A0
int PADdata1;   			//手柄2键值 [7:0]右7 左6 下5 上4 Start3 Select2 B1 A0

u8 *NES_RAM_Alloced;
u8 *NES_RAM;  // 2K 保持1024字节对齐
u8 *NES_SRAM; // 8K map to 6000-7FFF?
NES_header *RomHeader; 	//rom文件头
MAPPER *NES_Mapper;
MapperCommRes *MAPx;

void* MapperContext; // general mapper

u8* spr_ram;			//精灵RAM,256字节
ppu_data* ppu;			//ppu指针
u8* VROM_banks;
u8* VROM_tiles;

apu_t *apu; 			//apu指针
u16 *wave_buffers;
u16 *i2sbuf1; 			//音频缓冲帧,占用内存数 367*4 字节@22050Hz
u16 *i2sbuf2; 			//音频缓冲帧,占用内存数 367*4 字节@22050Hz

u16 num=0;
u8* romfile;			//nes文件指针,指向整个nes文件的起始地址.

__align(1024) unsigned int NES_BUFF[2][NES_DH + 64][NES_DW];
__align(4) unsigned int NES_Palette_argb8888[64];
unsigned char VPPU_FB[SCREEN_WIDTH * SCREEN_HEIGHT];
int buff_inx=0;
int buff_inx_n=0;

extern int emu_disk_led_show; // in desktop.c

//变换颜色缓存RGB565到ARGB8888
void NES_Palette_to_argb8888(void)
{
	int i = 0;
	for (i = 0; i < 64; i++) {
#if 0
		NES_Palette_argb8888[i] =
			((u64_t)0xFF << 24) |//A
			((((NES_Palette[i] >> 11) & 0x1F) << 3) << 16) | //R
			((((NES_Palette[i] >> 5) & 0x3F) << 2) << 8) | //G
			((((NES_Palette[i] >> 0) & 0x1F) << 3) << 0);  //B
#else
		NES_Palette_argb8888[i] = 0xFF000000 |
			(NES_Palette[i * 3 + 0] << 16) |
			(NES_Palette[i * 3 + 1] << 8) |
			(NES_Palette[i * 3 + 2] << 0);
#endif
	}
}

//defe初始化+16位色变32位色
void defe_color_init(void)
{
//色彩变换
	NES_Palette_to_argb8888();
//缩放
	Defe_Init();
	Defe_Config((u32)(NES_BUFF[0]), !emu_video_filter);
	Defe_Start();
}

void defe_restart(int no_filter)
{
	Defe_Stop();
	Defe_Config((u32)(NES_BUFF[0]), no_filter);
	Defe_Start();
}

void VPPU_PrepareFrame()
{
	VPPU_SetScreenPtr(VPPU_FB, 0);
}

void frame_post_draw(unsigned int* fb)
{
	int x, y;
	int disk_access;

	disk_access = NES_Mapper->Get(MGI_DISK_ACCESS);

#ifndef EVB_IO
	// GPIOE2 as FDD LED
	if (disk_access) {
		GPIO_RESET(GPIOE, 2);
	}  else {
		GPIO_SET(GPIOE, 2);
	}
#endif

	if (!emu_disk_led_show) disk_access = 0;

	// draw disk access LED
	for (y = 8; y < 12; y++) {
		for (x = 8; x < 14; x++) {
			fb[y * (NES_DW + 64) + (x + 32 + 256)] = disk_access ? 0xFF00FF00 : 0;
		}
	}
}

void VPPU_CommitFrame()
{
	static int index = 0;

	int x, y;

	unsigned int* bit = NES_BUFF[index];

	for (y = 0; y < 240; y++) {
		for (x = 0; x < 256; x++) {
			bit[y * (256 + 64) + x + 32] = NES_Palette_argb8888[VPPU_FB[y * SCREEN_WIDTH + x + 8]];
		}
	}

	frame_post_draw(NES_BUFF[index]);

	Defe_conversion_buff((u32)(NES_BUFF[index]));

	index ^= 1;
}

//////////////////////////////////////////////////////////////////////////////////////

vu8 system_task_return = 0; // 任务强制返回标志.

//加载ROM
//返回值:0,成功
//    1,内存错误
//    3,map错误
u8 nes_load_rom(void)
{
	u8* p;
	u8 i;
	u8 res = 0;

	p = (u8*)romfile;
	if (strncmp((const char*)p, "NES", 3) == 0) {
		RomHeader->ctrl_z            = p[3];
		RomHeader->num_16k_rom_banks = p[4];
		RomHeader->num_8k_vrom_banks = p[5];
		RomHeader->flags_1           = p[6];
		RomHeader->flags_2           = p[7];

		if (RomHeader->flags_1 & 4) p += 512;	//有512字节的trainer:
		if (RomHeader->num_8k_vrom_banks > 0) {	//存在VROM,进行预解码
			VROM_banks = p + 16 + (RomHeader->num_16k_rom_banks * 0x4000);
#if	NES_RAM_SPEED==1	//1:内存占用小 0:速度快
			VROM_tiles = VROM_banks;
#else
			VROM_tiles = mymalloc(SRAMIN, RomHeader->num_8k_vrom_banks * 8 * 1024);//这里可能申请多达1MB内存!!!
			if (VROM_tiles == 0)
				VROM_tiles = VROM_banks;//内存不够用的情况下,尝试VROM_titles与VROM_banks共用内存
			compile(RomHeader->num_8k_vrom_banks * 8 * 1024 / 16, VROM_banks, VROM_tiles);
#endif
		} else {
			VROM_banks = mymalloc(SRAMIN, 8 * 1024);
			VROM_tiles = mymalloc(SRAMIN, 8 * 1024);
			if (!VROM_banks || !VROM_tiles)
				res = 1;
		}

		VROM_1K_SIZE = RomHeader->num_8k_vrom_banks * 8;
		VROM_8K_SIZE = RomHeader->num_8k_vrom_banks;

		MapperNo = (RomHeader->flags_1 >> 4) | (RomHeader->flags_2 & 0xF0);
		if (RomHeader->flags_2 & 0x0E)
			MapperNo = RomHeader->flags_1 >> 4;//忽略高四位，如果头看起来很糟糕

		sysprintf("use map:%d\r\n", MapperNo);

		for (i = 0; i < 255; i++) { // 查找支持的Mapper号
			if (MapTab[i] == MapperNo)
				break;

			if (MapTab[i] == -1) {
				res = 3;
				break;
			}
		}

		if (res == 0) {
			switch (MapperNo) {
				case 1:
//					MAP1 = mymalloc(SRAMIN, sizeof(Mapper1Res));
//					if (!MAP1) res = 1;
					break;
				case 4:
				case 6:
				case 16:
				case 17:
				case 18:
				case 19:
				case 21:
				case 23:
				case 24:
				case 25:
				case 64:
				case 65:
				case 67:
				case 69:
				case 85:
				case 189:
					MAPx = mymalloc(SRAMIN, sizeof(MapperCommRes));
					if (!MAPx) res = 1;
					break;
				case 171:
					MapperContext = MAP171_New();
					if (!MapperContext) res = 1;
					break;
				default:
					break;
			}
		}
	}

	return res;	//返回执行结果
}

//释放内存
void nes_sram_free(void)
{
	myfree(SRAMIN,(void *)NES_RAM_Alloced);
	myfree(SRAMIN,(void *)NES_SRAM);
	myfree(SRAMIN,RomHeader);
	myfree(SRAMIN,NES_Mapper);
	myfree(SRAMIN,(void *)spr_ram);
	myfree(SRAMIN,ppu);
	myfree(SRAMIN,apu);
	myfree(SRAMIN,(void *)wave_buffers);
	myfree(SRAMIN,(void *)i2sbuf1);
	myfree(SRAMIN,(void *)i2sbuf2);
	myfree(SRAMIN,(void *)romfile);
	if((VROM_tiles!=VROM_banks)&&VROM_banks&&VROM_tiles)//如果分别为VROM_banks和VROM_tiles申请了内存,则释放
	{
		myfree(SRAMIN,(void *)VROM_banks);
		myfree(SRAMIN,(void *)VROM_tiles);
	}

	switch (MapperNo) {//释放map内存
		case 1: 			//释放内存
//			myfree(SRAMIN, MAP1);
			break;
		case 4:
		case 6:
		case 16:
		case 17:
		case 18:
		case 19:
		case 21:
		case 23:
		case 24:
		case 25:
		case 64:
		case 65:
		case 67:
		case 69:
		case 85:
		case 189:
			myfree(SRAMIN, MAPx);
			break;	 		//释放内存
		default:
			break;
	}

	NES_RAM_Alloced = 0;
	NES_SRAM = 0;
	RomHeader = 0;
	NES_Mapper = 0;
	spr_ram = 0;
	ppu = 0;
	apu = 0;
	wave_buffers = 0;
	i2sbuf1 = 0;
	i2sbuf2 = 0;
	romfile = 0;
	VROM_banks = 0;
	VROM_tiles = 0;
//	MAP1 = 0;
	MAPx = 0;
}

void nes_hard_reset(void)
{
	Joy_Reset();
	cpu6502_init();
	VPPU_Init();
	VPPU_Reset();
	apu_init(); //apu初始化
}

void nes_soft_reset(void)
{
	cpu6502_init();
}

//为NES运行申请内存
//romsize:nes文件大小
//返回值:0,申请成功
//       1,申请失败
u8 nes_sram_malloc(u32 romsize)
{
	NES_RAM_Alloced = mymalloc(SRAMIN, 0xC00);

	NES_SRAM     = mymalloc(SRAMIN, 0x2000);
	RomHeader    = mymalloc(SRAMIN, sizeof(NES_header));
	NES_Mapper   = mymalloc(SRAMIN, sizeof(MAPPER));
	spr_ram      = mymalloc(SRAMIN, 0x100);
	ppu          = mymalloc(SRAMIN, sizeof(ppu_data));
	apu          = mymalloc(SRAMIN, sizeof(apu_t));		//sizeof(apu_t)=  12588
	wave_buffers = mymalloc(SRAMIN, APU_PCMBUF_SIZE * 2);
	i2sbuf1      = mymalloc(SRAMIN, APU_PCMBUF_SIZE * 2);
	i2sbuf2      = mymalloc(SRAMIN, APU_PCMBUF_SIZE * 2);
	romfile      = mymalloc(SRAMIN, romsize);			//申请游戏rom空间,等于nes文件大小

	while (romfile == NULL) { //内存不够?释放主界面占用内存,再重新申请
		sysprintf("内存不足\r\n");

		for (;;);

		romfile = mymalloc(SRAMIN, romsize);//重新申请
	}

	if (!NES_RAM_Alloced || !NES_SRAM || !RomHeader || !NES_Mapper ||
		!spr_ram || !ppu || !apu || !wave_buffers
		|| !i2sbuf1 || !i2sbuf2 || !romfile) {
		sysprintf("err\r\n");
		nes_sram_free();
		return 1;
	}

	// alligned to 1024 byte
	NES_RAM = (u8*)(((u32)NES_RAM_Alloced + 1024) & ~1023);

	sysprintf("NES_RAM %08X aligned to %08X.\r\n", NES_RAM_Alloced, NES_RAM);

	memset(NES_SRAM,0,0x2000);				//清零
	memset(RomHeader,0,sizeof(NES_header));	//清零
	memset(NES_Mapper,0,sizeof(MAPPER));	//清零
	memset(spr_ram,0,0x100);				//清零
	memset(ppu,0,sizeof(ppu_data));			//清零
	memset(apu,0,sizeof(apu_t));			//清零
	memset(wave_buffers,0,APU_PCMBUF_SIZE*2);//清零
	memset(i2sbuf1,0,APU_PCMBUF_SIZE*2);	//清零
	memset(i2sbuf2,0,APU_PCMBUF_SIZE*2);	//清零
	memset(romfile,0,romsize);				//清零

	return 0;
}
//开始nes游戏
//pname:nes游戏路径
//返回值:
//0,正常退出
//1,内存错误
//2,文件错误
//3,不支持的map
u8 nes_load_for_fat(const char* pname)
{
#if 1
	FIL* file;
	UINT br;
	u8 res = 0;

	//defe初始化+16位色变32位色
	defe_color_init();

	/////////////////////////////////////////后加
	file = mymalloc(SRAMIN, sizeof(FIL));
	if (file == 0) return 1;						//内存申请失败.

	res = f_open(file, pname, FA_READ);
	if (res != FR_OK) {	//打开文件失败
		myfree(SRAMIN, file);
		sysprintf("文件打开失败\r\n");
		return 2;
	}

	sysprintf("文件打开成功\r\n");

	res = nes_sram_malloc(f_size(file));			//申请内存 ?
	if (res == 0) {
		sysprintf("初始化中 \r\n");
		f_read(file, romfile, f_size(file), &br);	//读取nes文件
		NESrom_crc32 = get_crc32(romfile+16, f_size(file)-16);//获取CRC32的值
		sysprintf("加载rom\r\n");

		res = nes_load_rom();						//加载ROM
		if (res == 0) {
			sysprintf("加载rom成功\r\n");
			Mapper_Init();						//map初始化
			Joy_Reset();
			sysprintf("a1\r\n");
			cpu6502_init();						//初始化6502,并复位
//			NES_Mapper->Reset();
//			cpu6502_reset();
//			sysprintf("a2\r\n");
			VPPU_Init();
			VPPU_Reset();
//			PPU_reset();						//ppu复位
			sysprintf("a3\r\n");
			apu_init(); 						//apu初始化

			sysprintf("进入模拟器中\r\n");
			nes_emulate_frame();				//进入NES模拟器主循环
			sysprintf("退出模拟器中\r\n");
			Mapper_Done();
			nes_sound_close();					//关闭声音输出
		}
	}

	sysprintf("exit 0\r\n");
	f_close(file);
	myfree(SRAMIN, file);//释放内存
	nes_sram_free();	//释放内存
	sysprintf("exit 1: %d\r\n", res);
	return res;
#else
	return 0;
#endif
}
u8 nes_xoff=0;	//显示在x轴方向的偏移量(实际显示宽度=256-2*nes_xoff)


//开始nes游戏
//pname:nes游戏路径
//返回值:
//0,正常退出
//1,内存错误
//2,文件错误
//3,不支持的map

//u8 nes_load_for_ram(unsigned char *dat, int dat_len)
u8 nes_load_for_flash(int offset, int dat_len)
{
	u8 res=0;
	sysprintf("内置[ROM] \r\n");

	//defe初始化+16位色变32位色
	defe_color_init();

	/////////////////////////////////////////后加
	res = nes_sram_malloc(dat_len);			//申请内存
	if (res == 0)
	{
		sys_spi_flash_read(SPI0, offset, romfile, dat_len);

		sysprintf("初始化中 \r\n");
		NESrom_crc32=get_crc32(romfile+16, dat_len-16);//获取CRC32的值
		sysprintf("加载rom: crc = %08X\r\n", NESrom_crc32);
		res=nes_load_rom();						//加载ROM
		if (res == 0) {
			sysprintf("加载rom成功\r\n");
			Mapper_Init();						//map初始化
			Joy_Reset();
			sysprintf("a1\r\n");
			cpu6502_init();						//初始化6502,并复位
			//cpu6502_reset();
			sysprintf("a2\r\n");
			VPPU_Init();
			VPPU_Reset();
//			PPU_reset();						//ppu复位
			sysprintf("a3\r\n");
			apu_init(); 						//apu初始化

			sysprintf("进入模拟器中\r\n");
			nes_emulate_frame();				//进入NES模拟器主循环
			sysprintf("退出模拟器中\r\n");
			nes_sound_close();					//关闭声音输出

		}
	}

	sysprintf("退出\r\n");
	nes_sram_free();	//释放内存
	return res;
}

// 0: no press
// 1: short press
// 2: long press
int check_user_key()
{
	// wait press
	if (0 == GPIO_READ(GPIOA, 0)) {
		delay_ms(10);
		if (0 == GPIO_READ(GPIOA, 0)) {
			int cnt = 0;

			// wait key release
			for (;;) {
				while (0 == GPIO_READ(GPIOA, 0)) {
					cnt++;
					delay_ms(10);
				}

				delay_ms(10);
				if (1 == GPIO_READ(GPIOA, 0))
					break;
			}

			return (cnt > 100) ? 2 : 1;
		}
	}

	return 0;
}

//读取游戏手柄数据
extern int joy1_status;
extern int joy2_status;

void nes_get_key(void)
{
	// Right7 Left6 Down5 Up4 Start3 Select2 B1 A0
	PADdata0 = joy1_status;
	PADdata1 = joy2_status;

#ifdef ENABLE_USER_KEY
	int ukey;

	ukey = check_user_key();
	if (ukey == 1) {
		sysprintf("Soft reset.\r\n");
		nes_soft_reset();
	} else if (ukey == 2) {
		sysprintf("Hard reset.\r\n");
		nes_hard_reset();
	}
#endif

	// WIN key: 0xE3/E7
	// MENU key: 0x65
	// ESC key: 0x29
	if (KEY_SCODE(0xE3) | KEY_SCODE(0xE7)) {
		Disable_Layer_Video();

		event_gui_done = 0;
		is_emu_running = 0;

		//sys_event_wait(event_gui_done);
		while (!event_gui_done) {
			vTaskDelay(100);
		}

		if (emu_hard_reset) {
			sysprintf("Hard reset.\r\n");
			nes_hard_reset();
			emu_hard_reset = 0;
		}

		// wait ESC and enter release
		while (KEY_SCODE(0x29) || KEY_SCODE(0x28) || KEY_SCODE(0x58))
			vTaskDelay(100);

		is_emu_running = 1;
		Enable_Layer_Video();
	}
}

int delta_clocks = 0;
int delta_cycles = 0;

void EmulationCPU(INT clocks)
{
	int req_cycles;

	req_cycles = (int)(clocks / 12);
	delta_clocks += clocks % 12;

	if (delta_clocks >= 12) {
		req_cycles++;
		delta_clocks -= 12;
	}

	req_cycles += delta_cycles;

	if (req_cycles > 0) {
		int emu_cycles;
		emu_cycles = cpu6502_run(req_cycles);
		delta_cycles = req_cycles - emu_cycles;
	}
}

//nes模拟器主循环
//extern int au_f;
extern int uart1_int_count;

void cpu_step_debug(int pc, int a, int s, int* regs)
{
	sysprintf("[%04X] A=%02X X=%02X Y=%02X P=%02X S=%02X\r\n",
		pc, a, regs[1], regs[2], regs[0], s);
}

void VNES_EmulateFrame(BOOL bDraw)
{
	INT	scanline = 0;

	const LPNESCONFIG nescfg = &NESCONFIG_DENDY;

	// NSFプレイヤの時
	//
	NES_scanline = scanline;

	while (TRUE) {
		VPPU_SetRenderScanline(scanline);

		if (scanline == 0) {
			// Dummy scan line
			EmulationCPU(nescfg->HDrawCycles);
			VPPU_FrameStart();
			VPPU_ScanlineNext();
			NES_Mapper->HSync(scanline);
			EmulationCPU(FETCH_CYCLES * 32);
			VPPU_ScanlineStart();
			EmulationCPU(FETCH_CYCLES * 10 + nescfg->ScanlineEndCycles);
		}
		else if (scanline < 240) {
			if (bDraw) {
				VPPU_Scanline(scanline, 1, 0);
			}
			else {
				if (!VPPU_IsSprite0(scanline)) {
					VPPU_DummyScanline(scanline);
				}
				else {
					VPPU_Scanline(scanline, 1, 0);
				}
			}

			EmulationCPU(nescfg->HDrawCycles);
			VPPU_ScanlineNext();
			NES_Mapper->HSync(scanline);
			EmulationCPU(FETCH_CYCLES * 32);
			VPPU_ScanlineStart();
			EmulationCPU(FETCH_CYCLES * 10 + nescfg->ScanlineEndCycles);
		}
		else if (scanline == 240) {
			NES_Mapper->VSync();
			EmulationCPU(nescfg->HDrawCycles);
			NES_Mapper->HSync(scanline);
			EmulationCPU(nescfg->HBlankCycles);
		}
		else if (scanline <= nescfg->TotalScanlines - 1) {
			//pad->VSync();
			// VBLANK期間
			if (scanline == nescfg->TotalScanlines - 1) {
				VPPU_VBlankEnd();
			}

			if (scanline == nescfg->VBlankLine) {
				VPPU_VBlankStart();
				if (VPPU_IsNMIEnabled()) {
					cpu6502_nmi();
				}
			}

			EmulationCPU(nescfg->HDrawCycles);
			NES_Mapper->HSync(scanline);
			EmulationCPU(nescfg->HBlankCycles);

			if (scanline == nescfg->TotalScanlines - 1) {
				break;
			}
		}

		scanline++;
		NES_scanline = scanline;
	}
}

void nes_emulate_frame(void)
{
	int frame_count = 0, time=0;
	u8 nes_frame = 0;

	is_emu_running = 1;

	nes_sound_open(0, 0);

#ifdef ENABLE_USER_KEY
	GPIO_Congif(GPIOA, 0, GPIO_Mode_IN, GPIO_PuPd_UP);
#endif

	time = Read_time_ms();

	Enable_Layer_Video();

	while (1) {
		BOOL bDraw = (NES_SKIP_FRAME == 0) || (nes_frame != 0);

		VPPU_PrepareFrame();
		VNES_EmulateFrame(bDraw);

		apu_soundoutput();//输出游戏声音

		if (bDraw) VPPU_CommitFrame();

		// update kbd led
		kbd_led_ctl = NES_Mapper->Get(MGI_KBD_LED);
		nes_get_key();

		nes_frame_cnt++;
		frame_count++;

		if (NES_SKIP_FRAME) {
			nes_frame++;
			if (nes_frame > NES_SKIP_FRAME)
				nes_frame = 0;//跳帧
		}

		if (system_task_return)
			break;//TPAD返回

		//显示帧数
		if ((Read_time_ms() - time) > 1000) {
			sysprintf("Frame=%d AUDIO=%d uart1=%d\r\n", frame_count, 0, uart1_int_count);
			frame_count = 0;
			uart1_int_count = 0;
			//au_f=0;
			time = Read_time_ms();
		}
	}

	nes_sound_close();

	is_emu_running = 0;
}


//在6502.s里面被调用
void debug_6502(u16 reg0, u8 reg1)
{
	sysprintf("6502 error: %x, %d\r\n", reg0, reg1);
}
//////////////////////////////////////////////////////////////////////////////////
//nes,音频输出支持部分

//打开dac传送

int nes_sound_open(int samples_per_sync, int sample_rate)
{
	owa_init(48000);
	owa_start();
	return 1;
}

//NES关闭音频输出
void nes_sound_close(void)
{
	owa_stop();
}

//NES音频输出到DAC缓存
//APU_PCMBUF_SIZE
//short pcm_buf_2x[APU_PCMBUF_SIZE * 2];
void nes_apu_fill_buffer(int samples, u16* wavebuf)
{
#if 1
	owa_write_mono((const short*)wavebuf, samples);
#else
	int i;
	short* src;
	short* dst;

	src = wavebuf;
	dst = pcm_buf_2x;
	for (i = 0; i < samples; i++) {
		*dst++ = *src++;
		*dst++ = 0;
	}

	owa_write_mono(pcm_buf_2x, samples * 2);
#endif
}
